const fs = require('fs');
const path = require('path');
const controllerLoader = require('./loaders/controller');

const mounter = {
  controller: {},
  service: {},
  middleware: {}
};

init(mounter);
module.exports = mounter;

/**
 * @function init 初始化挂载目录
 * @return {Object} 返回导入对象
 */
function init(mounter) {
  const keys = Object.keys(mounter);
  for (let i = 0; i < keys.length; i++) {
    const item = keys[i];
    const options = {
      exports: mounter[item],
      directory: path.resolve(process.cwd(), `src/${item}`)
    };
    if (item === 'controller') {
      options.loader = controllerLoader;
    }
    loadDirectory(options);
  }
}

/**
 * @function loadDirectory 目录加载器, 按目录层次组装并加载
 * @param {Object} exports 导出目标对象
 * @param {String} directory 目录路径
 * @param {Object} options
 * options: {
 *  capitalizeClass: {Boolean} 是否格式化类首字母(大写) 默认: false
 *  loader: {Function} 自定义加载器
 * }
 * @return {Object} 返回导入对象
 */
function loadDirectory(options = {}) {
  // 默认配置
  options = Object.assign({
    capitalizeClass: false,
    loader: null
  }, options);
  let {
    exports,
    directory,
    capitalizeClass,
    loader
  } = options;

  if (!fs.existsSync(directory)) {
    return;
  }
  fs.readdirSync(directory).forEach((file, index) => {
    let fullPath = path.join(directory + '/' + file);
    let stat = fs.statSync(fullPath);

    if (stat.isDirectory()) {
      exports[file] = {};
      let configs = Object.assign({}, options);
      configs.exports = exports[file];
      configs.directory = fullPath;
      loadDirectory(configs);
    } else {
      let match = /(\w+)\.js$/.exec(file);
      if (match) {
        file = capitalizeClass ? capitalizeClassName(match[1]) : match[1];

        // 这里需要注意，如果同目录下有一个js文件和一个目录相同，这需要将此js文件重命名
        if (exports[file]) {
          let message = `\n\t同一个目录下不能有相同的js文件和目录名相同的文件存在！\n\t相同文件名为：${file}\n\t建议将js文件移动到${file}目录下更名为index！\n`;
          throw new Error(message);
        }
        exports.__defineGetter__(file, () => {
          if (typeof loader === 'function') {
            return loader(require(fullPath));
          } else {
            return require(fullPath);
          }
        });
      }
    }
    return exports;
  });
}

/**
 * @function capitalizeClassName 格式化大写类首字母
 * @param {String} string 传入的字符串
 * @return {String}
 */
function capitalizeClassName(string) {
  return string.replace(/\b[a-z]/g, char => char.toUpperCase());
}
